// 版权归Go作者所有。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package poll

import "sync/atomic"

// fdMutex是一种专门的同步原语，用于管理fd的生存期，并序列化对fd上的读取、写入和关闭
// 方法的访问。
type fdMutex struct {
	state uint64
	rsema uint32
	wsema uint32
}

// fdMutex.state按如下方式组织：
// 1位-FD是否关闭，如果设置，所有后续锁定操作都将失败。
// 读取操作的1位锁。
// 写入操作的1位锁。
// 20位—引用的总数（读+写+杂项）。
// 20位—未完成读取等待的数量。
// 20位—未完成写入等待程序的数量。
const (
	mutexClosed  = 1 << 0
	mutexRLock   = 1 << 1
	mutexWLock   = 1 << 2
	mutexRef     = 1 << 3
	mutexRefMask = (1<<20 - 1) << 3
	mutexRWait   = 1 << 23
	mutexRMask   = (1<<20 - 1) << 23
	mutexWWait   = 1 << 43
	mutexWMask   = (1<<20 - 1) << 43
)

const overflowMsg = "too many concurrent operations on a single file or socket (max 1048575)"

// 读取操作必须执行rwlock（true）/rwlock（true）。
// 
// 写入操作必须执行rwlock（false）/rwunlock（false）。
// 
// 其他操作必须执行递增/递减操作。
// 其他操作包括setsockopt和setDeadline等函数。
// 他们需要使用incref/decref来确保他们在同时关闭呼叫的情况下在
// 上操作正确的fd（否则fd可以在他们脚下关闭）。
// 
// 关闭操作必须执行递增关闭/递减操作。

// incref添加对mu的引用。
// 报告mu是否可用于读写。
func (mu *fdMutex) incref() bool {
	for {
		old := atomic.LoadUint64(&mu.state)
		if old&mutexClosed != 0 {
			return false
		}
		new := old + mutexRef
		if new&mutexRefMask == 0 {
			panic(overflowMsg)
		}
		if atomic.CompareAndSwapUint64(&mu.state, old, new) {
			return true
		}
	}
}

// IncremerFandClose将mu的状态设置为关闭。
// 如果文件已经关闭，则返回false。
func (mu *fdMutex) increfAndClose() bool {
	for {
		old := atomic.LoadUint64(&mu.state)
		if old&mutexClosed != 0 {
			return false
		}
		// 标记为关闭并获取引用。
		new := (old | mutexClosed) + mutexRef
		if new&mutexRefMask == 0 {
			panic(overflowMsg)
		}
		// 删除所有读写等待程序。
		new &^= mutexRMask | mutexWMask
		if atomic.CompareAndSwapUint64(&mu.state, old, new) {
			// 唤醒所有读写服务生，
			// 他们将在唤醒后观察关闭标志。
			for old&mutexRMask != 0 {
				old -= mutexRWait
				runtime_Semrelease(&mu.rsema)
			}
			for old&mutexWMask != 0 {
				old -= mutexWWait
				runtime_Semrelease(&mu.wsema)
			}
			return true
		}
	}
}

// decref从mu中删除引用。
// 报告是否没有剩余引用。
func (mu *fdMutex) decref() bool {
	for {
		old := atomic.LoadUint64(&mu.state)
		if old&mutexRefMask == 0 {
			panic("inconsistent poll.fdMutex")
		}
		new := old - mutexRef
		if atomic.CompareAndSwapUint64(&mu.state, old, new) {
			return new&(mutexClosed|mutexRefMask) == mutexClosed
		}
	}
}

// lock添加对mu的引用并锁定mu。
// 它报告mu是否可用于读取或写入。
func (mu *fdMutex) rwlock(read bool) bool {
	var mutexBit, mutexWait, mutexMask uint64
	var mutexSema *uint32
	if read {
		mutexBit = mutexRLock
		mutexWait = mutexRWait
		mutexMask = mutexRMask
		mutexSema = &mu.rsema
	} else {
		mutexBit = mutexWLock
		mutexWait = mutexWWait
		mutexMask = mutexWMask
		mutexSema = &mu.wsema
	}
	for {
		old := atomic.LoadUint64(&mu.state)
		if old&mutexClosed != 0 {
			return false
		}
		var new uint64
		if old&mutexBit == 0 {
			// 锁是免费的，获取它。
			new = (old | mutexBit) + mutexRef
			if new&mutexRefMask == 0 {
				panic(overflowMsg)
			}
		} else {
			// 等待锁定。
			new = old + mutexWait
			if new&mutexMask == 0 {
				panic(overflowMsg)
			}
		}
		if atomic.CompareAndSwapUint64(&mu.state, old, new) {
			if old&mutexBit == 0 {
				return true
			}
			runtime_Semacquire(mutexSema)
			// 信号员已减去mutexWait。
		}
	}
}

// unlock从mu中删除引用并解锁mu。
// 报告是否没有剩余的引用。
func (mu *fdMutex) rwunlock(read bool) bool {
	var mutexBit, mutexWait, mutexMask uint64
	var mutexSema *uint32
	if read {
		mutexBit = mutexRLock
		mutexWait = mutexRWait
		mutexMask = mutexRMask
		mutexSema = &mu.rsema
	} else {
		mutexBit = mutexWLock
		mutexWait = mutexWWait
		mutexMask = mutexWMask
		mutexSema = &mu.wsema
	}
	for {
		old := atomic.LoadUint64(&mu.state)
		if old&mutexBit == 0 || old&mutexRefMask == 0 {
			panic("inconsistent poll.fdMutex")
		}
		// 放下锁、放下引用并唤醒读服务生（如果存在）。
		new := (old &^ mutexBit) - mutexRef
		if old&mutexMask != 0 {
			new -= mutexWait
		}
		if atomic.CompareAndSwapUint64(&mu.state, old, new) {
			if old&mutexMask != 0 {
				runtime_Semrelease(mutexSema)
			}
			return new&(mutexClosed|mutexRefMask) == mutexClosed
		}
	}
}

// 在运行时包中实现。
func runtime_Semacquire(sema *uint32)
func runtime_Semrelease(sema *uint32)

// incref添加对fd的引用。
// 当fd不能使用时返回一个错误。
func (fd *FD) incref() error {
	if !fd.fdmu.incref() {
		return errClosing(fd.isFile)
	}
	return nil
}

// decref从fd中删除引用。
// 当fd的状态设置为closed且没有剩余引用时，它也会关闭fd。
func (fd *FD) decref() error {
	if fd.fdmu.decref() {
		return fd.destroy()
	}
	return nil
}

// readLock添加对fd的引用并锁定fd进行读取。
// 当fd不能用于读取时返回一个错误。
func (fd *FD) readLock() error {
	if !fd.fdmu.rwlock(true) {
		return errClosing(fd.isFile)
	}
	return nil
}

// readUnlock从fd中删除引用并解锁fd以进行读取。
// 当fd的状态设置为closed时，它也会关闭fd，并且没有剩余的引用。
func (fd *FD) readUnlock() {
	if fd.fdmu.rwunlock(true) {
		fd.destroy()
	}
}

// writeLock添加对fd的引用并锁定fd进行写入。
// 当fd不能用于写入时返回一个错误。
func (fd *FD) writeLock() error {
	if !fd.fdmu.rwlock(false) {
		return errClosing(fd.isFile)
	}
	return nil
}

// writeUnlock从fd中删除引用并解除fd的写入锁定。
// 当fd的状态设置为closed时，它也会关闭fd，并且没有剩余的引用。
func (fd *FD) writeUnlock() {
	if fd.fdmu.rwunlock(false) {
		fd.destroy()
	}
}
